﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;

namespace RAP.Framework.Libary.Utils
{
	/// <summary>
	/// 对象浅克隆属性工具
	/// </summary>
	/// <typeparam name="T"></typeparam>
	public static class ObjectClone<T>
	{
		private static readonly Func<T, T, T> funcClone = CreateFuncCache();

		private static Func<T, T, T> CreateFuncCache( )
		{
			var type = typeof( T );
			var parameterSrcExp = Expression.Parameter( type, "p" );
			var parameterTargetExp = Expression.Parameter( type, "t" );
			var propertyExps = new List<Expression>();
			var returnTarget = Expression.Label( type );
			foreach ( var p in type.GetProperties() )
			{
				if ( !p.CanWrite )
				{
					continue;
				}
				var propertySrcExp = Expression.Property( parameterSrcExp, p );
				var propertyTargetExp = Expression.Property( parameterTargetExp, p );
				propertyExps.Add( Expression.Assign( propertyTargetExp, propertySrcExp ) );
			}

			propertyExps.Add( Expression.Return( returnTarget, parameterTargetExp, type ) );
			propertyExps.Add( Expression.Label( returnTarget, Expression.Constant( null, type ) ) );
			var exp = Expression.Block( propertyExps.ToArray() );
			var lambda = Expression.Lambda<Func<T, T, T>>( exp, new ParameterExpression[]
			{
				parameterSrcExp,
				parameterTargetExp
			} );
			return lambda.Compile();
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="srcObj"></param>
		/// <param name="targetObj"></param>
		/// <returns></returns>
		public static T Clone( T srcObj, T targetObj )
		{
			return funcClone( srcObj, targetObj );
		}
	}
}
